package com.guguguweb.rpc.codec;

import com.guguguweb.rpc.entity.RpcRequest;
import com.guguguweb.rpc.entity.RpcResponse;
import com.guguguweb.rpc.enumeration.PackageType;
import com.guguguweb.rpc.enumeration.RpcError;
import com.guguguweb.rpc.exception.RpcException;
import com.guguguweb.rpc.serializer.CommonSerializer;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ReplayingDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;


//消息的定义为 ：消息头 + 消息体
//消息头：MAGIC_NUMBER + 本次请求类型 + 序列化器的编号 + 消息体的长度
//消息体：即为 发送的Java序列化之后的字节数组

/**
 * netty的通用message译码器，将消息字节数组变成我们的Java对象
 */
public class MessageDecoder extends ReplayingDecoder {

    private static final Logger log = LoggerFactory.getLogger(MessageDecoder.class);
    private static final int MAGIC_NUMBER = 0x666ABC;

    @Override
    public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        log.debug("从对象流里面解码");
        int magic = in.readInt();
        if(magic != MAGIC_NUMBER){
            log.error("魔数匹配错误 , ：{}",magic);
            throw new RpcException(RpcError.UNKNOWN_PROTOCOL);
        }
        int packageCode = in.readInt();
        Class<?> packageClass;
        if(packageCode == PackageType.REQUEST_PACK.getCode()){
            packageClass = RpcRequest.class;
        }else if (packageCode == PackageType.RESPONSE_PACK.getCode()){
            packageClass = RpcResponse.class;
        }else {
            log.error("消息类型匹配错误：{}", packageCode);
            throw new RpcException(RpcError.UNKNOWN_PACKAGE_TYPE);
        }
        int serializerCode = in.readInt();
        CommonSerializer serializer = CommonSerializer.getByCode(serializerCode);
        if(serializer == null){
            log.error("不识别的反序列化器：{}", serializerCode);
            throw new RpcException(RpcError.UNKNOWN_SERIALIZER);
        }
        int length = in.readInt();
        byte[] bytes = new byte[length];
        in.readBytes(bytes);
        Object obj = serializer.deserialize(bytes, packageClass);
        out.add(obj);
    }
}
